package com.mt.restaurant.service.material.impl;

import com.mt.restaurant.dao.material.SupplyMaterialDao;

import com.mt.common.core.exception.BusinessException;
import com.mt.common.core.web.base.PageDTO;
import com.mt.common.core.web.base.PageResultDTO;
import com.mt.common.core.web.base.BaseEntity;
import com.mt.common.core.web.BaseService;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.mt.restaurant.entity.material.SupplyMaterial;
import com.mt.restaurant.service.material.SupplyMaterialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional
public class SupplyMaterialServiceBean extends BaseService implements SupplyMaterialService {

    private static Logger logger = LogManager.getLogger();

	@Autowired
	private SupplyMaterialDao supplyMaterialDao;

	@Resource
	private RedisTemplate<String, List<SupplyMaterial>> redisTemplate;

	@Autowired
	StringRedisTemplate stringRedisTemplate;

	/**
	 * 根据分页参数查询供应原材料集合
	 *
	 * @param pageDTO 分页条件
	 */
	@Override
	public PageResultDTO findSupplyMaterials(PageDTO pageDTO){
        if(pageDTO.getCurrentPage() != null){
			pageDTO.setStartIndex((pageDTO.getCurrentPage()-1)*pageDTO.getPageSize());
		}
		//TODO:请在此校验参数的合法性
		this.validateFindSupplyMaterials(pageDTO);
		List<SupplyMaterial> supplyMaterialDTOS = this.supplyMaterialDao.findSupplyMaterials(pageDTO);

		Long totalCount = this.supplyMaterialDao.findSupplyMaterialTotalCount(pageDTO);

		PageResultDTO pageResultDTO = new PageResultDTO();
		pageResultDTO.setTotalCount(totalCount);
		pageResultDTO.setDatas(supplyMaterialDTOS);

		return pageResultDTO;
	}

	/**
	 * 查询全部供应原材料集合
	 *
	 */
	@Override
	public List<SupplyMaterial> findAllSupplyMaterials(){
		return this.supplyMaterialDao.findAllSupplyMaterials();
	}

	/**
	 * 查询所有供应原材料集合(只提取ID 和 Name)
	 *
	 */
	@Override
	public List<SupplyMaterial> findAllSupplyMaterialsWithIdName(){
		//TODO:请在此校验参数的合法性
		this.validateFindAllSupplyMaterialsWithIdName();
		return this.supplyMaterialDao.findAllSupplyMaterialsWithIdName();
	}

	/**
	 * 根据名称查询供应原材料集合(只提取ID 和 Name)
	 *
	 * @param supplyMaterialName 名称
	 */
	@Override
	public List<SupplyMaterial> findSupplyMaterialsWithIdNameByName(String supplyMaterialName){
		//TODO:请在此校验参数的合法性
		this.validateFindSupplyMaterialsWithIdNameByName(supplyMaterialName);
		//TODO:缓存取对应参数
		Set<String> keys = stringRedisTemplate.keys("searchData:SupplyMaterial_where_supplyMaterialName_" + supplyMaterialName);
		List<SupplyMaterial> supplyMaterials = new ArrayList<>();
		if (keys.isEmpty()) {
		supplyMaterials = this.supplyMaterialDao.findSupplyMaterialsWithIdNameByName(supplyMaterialName);
		redisTemplate.opsForValue().set("searchData:SupplyMaterial_where_supplyMaterialName_" + supplyMaterialName, supplyMaterials, 30, TimeUnit.DAYS);
		} else {
		supplyMaterials = redisTemplate.opsForValue().get("searchData:SupplyMaterial_where_supplyMaterialName_" + supplyMaterialName);
		}
		return supplyMaterials;
	}

	/**
	 * 根据ID查询指定的供应原材料(只提取ID 和 Name)
	 *
	 * @param supplyMaterialId Id
	 */
	@Override
	public SupplyMaterial findSupplyMaterialsWithIdNameById(Long supplyMaterialId){
		//TODO:请在此校验参数的合法性
		this.validateFindSupplyMaterialsWithIdNameById(supplyMaterialId);
		return this.supplyMaterialDao.findSupplyMaterialsWithIdNameById(supplyMaterialId);
	}

	/**
	 * 根据ID查询指定的供应原材料
	 *
	 * @param supplyMaterialId Id
	 */
	@Override
	public SupplyMaterial findSupplyMaterial(Long supplyMaterialId){
		//TODO:请在此校验参数的合法性
		this.validateFindSupplyMaterial(supplyMaterialId);
		return this.supplyMaterialDao.findSupplyMaterial(supplyMaterialId);
	}

	/**
	 * 根据ID查询指定的供应原材料(包含外键)
	 *
	 * @param supplyMaterialId Id
	 */
	@Override
	public SupplyMaterial findSupplyMaterialWithForeignName(Long supplyMaterialId){
		//TODO:请在此校验参数的合法性
		this.validateFindSupplyMaterialWithForeignName(supplyMaterialId);
		return this.supplyMaterialDao.findSupplyMaterialWithForeignName(supplyMaterialId);
	}

	/**
	 * 新增供应原材料
	 *
	 * @param supplyMaterial 实体对象
	 */
	@Override
	public SupplyMaterial saveSupplyMaterial(SupplyMaterial supplyMaterial){
		//TODO:请在此校验参数的合法性
		this.validateSaveSupplyMaterial(supplyMaterial);
		//TODO:填充公共参数
		this.setSavePulicColumns(supplyMaterial);
		Long rows = this.supplyMaterialDao.saveSupplyMaterial(supplyMaterial);
		if(rows != 1)
		{
			String error = "新增保存供应原材料出错，数据库应该返回1,但返回了 "+rows;
			throw new BusinessException(error);
		}
		return supplyMaterial;
	}

	/**
	 * 批量新增
	 * 新增需要保存的供应商材料列表。
	 *
	 * @param supplyMaterials 新增供应商材料的信息列表
	 */
	private void saveSupplyMaterials(List<SupplyMaterial> supplyMaterials,Long supplierId) {
		//验证合法性，填充公共参数
		supplyMaterials.forEach(supplyMaterial -> {
			this.setSavePulicColumns(supplyMaterial);
			supplyMaterial.setSupplierId(supplierId);
//			supplyMaterial.setStatus("启用");
			Long rows = this.supplyMaterialDao.saveSupplyMaterial(supplyMaterial);
			if (rows != 1) {
				String error = "新增保存供应商材料出错，数据库应该返回1,但返回了 " + rows;
				throw new BusinessException(error);
			}
		});
	}

	/**
	 * 更新供应原材料
	 *
	 * @param supplyMaterial 实体对象
	 */
	@Override
	public SupplyMaterial updateSupplyMaterial(SupplyMaterial supplyMaterial){
		//TODO:请在此校验参数的合法性
		this.validateUpdateSupplyMaterial(supplyMaterial);
		Long rows = this.supplyMaterialDao.updateSupplyMaterial(supplyMaterial);
		if(rows != 1)
		{
			String error = "修改保存供应原材料出错，数据库应该返回1,但返回了 "+rows+",数据可能被删除";
			throw new BusinessException(error);
		}
		return supplyMaterial;
	}

	@Override
	public SupplyMaterial updateSupplyMaterialFailuresNum(Long supplyMaterialId) {
		Long rows = this.supplyMaterialDao.updateSupplyMaterialFailuresNum(supplyMaterialId);
		if(rows!=1){
			String error = "修改保存供应原材料出错，数据库应该返回1,但返回了 "+rows+",数据可能被删除";
			throw new BusinessException(error);
		}
		return null;
	}

	/**
	 * 批量修改
	 * 对需要修改的供应商材料列表的信息进行修改。
	 *
	 * @param supplyMaterials 需要修改的供应商材料信息
	 */
	private void updateSupplyMaterials(List<SupplyMaterial> supplyMaterials) {
		//无实体类引用再修改状态时判断，
		supplyMaterials.forEach(supplyMaterial -> {
			Long rows = this.supplyMaterialDao.updateSupplyMaterial(supplyMaterial);
			if (rows != 1) {
				String error = "修改保存供应商材料出错，数据库应该返回" + 1 +
						",但返回了 " + rows + ",数据可能被删除";
				throw new BusinessException(error);
			}
		});
	}

	/**
	 * 采购后减少供应商材料库存
	 *
	 * @param supplyMaterialId
	 * @param quantity
	 */
	public void updateSupplyMaterialStockById(Long supplyMaterialId, Double quantity) {
		SupplyMaterial supplyMaterial = this.supplyMaterialDao.findSupplyMaterial(supplyMaterialId);
		Double stock = supplyMaterial.getStock()-quantity;
		if(stock<0){
			String error = "当前供应商已没有足够材料库存，无法完成采购";
			throw new BusinessException(error);
		}
		supplyMaterial.setStock(stock);
		Long rows = this.supplyMaterialDao.updateSupplyMaterial(supplyMaterial);
		if(rows!=1){
			String error = "修改保存供应商材料出错，数据库应该返回" + 1 +
					",但返回了 " + rows + ",数据可能被删除";
			throw new BusinessException(error);
		}
	}

	/**
	 * 根据ID删除供应原材料
	 *
	 * @param supplyMaterialId ID
	 */
	@Override
	public void deleteSupplyMaterial(Long supplyMaterialId){
		//TODO:请在此校验参数的合法性
		this.validateDeleteSupplyMaterial(supplyMaterialId);

		Map<Class<? extends BaseEntity>,EntityUsage> entityUsageMap = this.checkForeignEntity(SupplyMaterial.class, supplyMaterialId);
		if(entityUsageMap != null && entityUsageMap.size() >0){
			StringBuilder errors = new StringBuilder();
			errors.append("计划删除的数据正在被以下数引用\n");
			for(EntityUsage entityUsage : entityUsageMap.values()){
				errors.append("\t").append(entityUsage.getEntityLabel()).append("\n");
				for(Map.Entry<Long,String> entry : entityUsage.getUsageIdNames().entrySet() ){
					errors.append("\t\t").append(entry.getKey()).append("\t").append(entry.getValue()).append("\n");
				}
			}
			errors.append("，不能删除，请检查处理后再删除");
			throw  new BusinessException(errors.toString());
		}

		Long rows = this.supplyMaterialDao.deleteSupplyMaterial(supplyMaterialId);
		if(rows != 1){
			String error = "删除供应原材料出错，数据可能已经被删除";
			throw new BusinessException(error);
		}
	}

	@Override
	public List<SupplyMaterial> changeSupplyMateialById(Long supplierId, List<SupplyMaterial> supplyMaterials) {
		if(supplyMaterials==null){
			return null;
		}

		List<SupplyMaterial> supplyMaterialsForSave = new ArrayList<>();
		List<SupplyMaterial> supplyMaterialsForUpdate = new ArrayList<>();

		String error;
		final String SUPPLIER_ID_FIELD = "supplierId";

		Map<String, Object> filter = new HashMap<>();
		filter.put(SUPPLIER_ID_FIELD, supplierId);
		PageDTO pageDTO = PageDTO.create(filter);
		List<SupplyMaterial> dbSupplyMaterials = (List<SupplyMaterial>) findSupplyMaterials(pageDTO).getDatas();


		//因为新增供应商材料处理较多，因此单独设置直接处理。
		if (dbSupplyMaterials == null || dbSupplyMaterials.size() == 0) {
			return changeSupplyMaterials(supplyMaterials, null,supplierId);
		}

		for (SupplyMaterial supplyMaterial : supplyMaterials) {
			if (supplyMaterial.getEid() != null) {
				//筛选对应Eid的对象
				List<SupplyMaterial> collect = dbSupplyMaterials.stream().filter(supplyMaterialInDB ->
						supplyMaterialInDB.getEid().equals(supplyMaterial.getEid())
				).collect(Collectors.toList());

				if (collect.size() != 1) {
					error = "数据传输错误," +
							"本应该筛选Eid=" + supplyMaterial.getEid() + "的结果为1," +
							"结果输出" + collect.size() +
							",请检查对应的数据是否已经被删除或者被修改";
					throw new BusinessException(error);
				}

				/*if ("停用".equals(collect.get(0).getStatus()) && "停用".equals(supplyMaterial.getStatus())) {
					//前后状态为停用，不修改
					continue;
				}*/
				//删除查询过的对象，剩下没被查询到的
//				SupplyMaterial supplyMaterialTemp = collect.get(0);
				dbSupplyMaterials.remove(collect.get(0));

				//判断是否有更改
				supplyMaterialsForUpdate.add(supplyMaterial);

			} else {
				supplyMaterialsForSave.add(supplyMaterial);
			}
		}
		List<SupplyMaterial> dealSupplyMaterials = changeSupplyMaterials(supplyMaterialsForSave, supplyMaterialsForUpdate,supplierId);
		System.out.println("处理了" + dealSupplyMaterials.size() +
				"条数据，更新了" + supplyMaterialsForUpdate.size() +
				"条，新增了" + supplyMaterialsForSave.size() + "条");


		return supplyMaterials;

	}

	private List<SupplyMaterial> changeSupplyMaterials(List<SupplyMaterial> supplyMaterialsForSave, List<SupplyMaterial> supplyMaterialsForUpdate, Long supplierId) {
		List<SupplyMaterial> supplyMaterials = new ArrayList<>();

		if (supplyMaterialsForUpdate != null && supplyMaterialsForUpdate.size() != 0) {
			updateSupplyMaterials(supplyMaterialsForUpdate);
		}
		if (supplyMaterialsForSave != null && supplyMaterialsForSave.size() != 0) {
			saveSupplyMaterials(supplyMaterialsForSave,supplierId);
		}

		return supplyMaterials;
	}

	//TODO:---------------验证-------------------

	private void validateFindSupplyMaterials(PageDTO pageDTO) {
	//TODO:请使用下面方法添加数据过滤条件
	//		pageDTO.addFilter("creatorId",this.getLoginUserId());
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}

	private void validateFindSupplyMaterialsWithIdNameByName(String supplyMaterialName) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}


	private void validateFindAllSupplyMaterialsWithIdName() {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}

	private void validateFindSupplyMaterialsWithIdNameById(Long supplyMaterialId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}

	private void validateFindSupplyMaterial(Long supplyMaterialId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}

	private void validateFindSupplyMaterialWithForeignName(Long supplyMaterialId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}

	private void validateSaveSupplyMaterial(SupplyMaterial supplyMaterial) {
	//不为空判断
	if (supplyMaterial.getEid() != null || supplyMaterial.getCreatorId() != null || supplyMaterial.getCreateDatetime() != null) {
	throw new BusinessException("非法请求");
	}
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}

	private void validateUpdateSupplyMaterial(SupplyMaterial supplyMaterial) {
	//不为空判断
	if (supplyMaterial.getEid() == null) {
	throw new BusinessException("唯一标识不能为空");
	}
	//是否存在判断
	if (this.supplyMaterialDao.findSupplyMaterialTotalCount(PageDTO.create(SupplyMaterial.FIELD_ID, supplyMaterial.getEid())) == 0) {
	throw new BusinessException("修改的供应原材料 " + supplyMaterial.getName() + " 不存在，修改失败，请重试或联系管理员");
	}
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}

	private void validateDeleteSupplyMaterial(Long supplyMaterialId) {
	//TODO:请完善数据校验规则和数据权限判断，如果有问题请抛出异常，参看下面validateUpdateSupplyMaterial()写法
	}

	@Override
	public boolean canDownloadAttachment(String formName, Long id) {
	return true;
	}

	/**
	 * 验证更新的数据是否合法
	 *
	 * @param supplyMaterial 供应商材料列表
	 */
	private void validateUpdateSupplyMaterialWithoutDB(SupplyMaterial supplyMaterial) {
		if (supplyMaterial.getEid() == null) {
			throw new BusinessException("更新时，唯一标识不能为空");
		}
		if (supplyMaterial.getMaterialId() == null) {
			throw new BusinessException("数据校验报错，请检查实体材料Id");
		}

	}
}
